Working with Thread Constructors, Priorities, and Methods in Java
Course: Core Java Training
Topic: Working with Thread Constructors, Priorities, and Methods
Course Link: Core Java Training Course
Demo Link: Register for a Free Course Demo
Website: JustAcademy
1. Introduction to Thread Constructors, Priorities, and Methods
Multithreading is an important feature of Java that allows multiple threads to execute concurrently within a program. A thread represents an independent path of execution. Threads are useful for background processing, file operations, network communication, responsive applications, and other tasks that can run concurrently.
Java provides the Thread class in the java.lang package. It contains constructors for creating thread objects and methods for starting, naming, monitoring, prioritizing, and coordinating threads.
Understanding thread constructors, priorities, and methods helps developers create organized multithreaded programs and manage concurrent tasks more effectively.
2. Learning Objectives
- Understand the purpose of the Java
Thread class.
- Learn commonly used thread constructors.
- Create threads using different constructors.
- Understand thread priorities and their constants.
- Use important thread methods in Java programs.
- Learn thread naming, sleeping, joining, and interruption.
- Understand common mistakes and multithreading best practices.
3. What Is a Thread in Java?
A thread is a lightweight unit of execution within a process. A Java application can contain multiple threads that perform different tasks concurrently.
For example, an application might use one thread to download a file while another updates the user interface and another processes background information.
Example: A Simple Thread
class MyThread extends Thread {
@Override
public void run() {
System.out.println("Thread is executing");
}
}
public class Main {
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.start();
}
}
Explanation:
extends Thread creates a class that inherits from the Thread class.
run() contains the task performed by the thread.
new MyThread() creates a thread object.
start() requests the JVM to schedule the thread for execution.
Important: Calling start() starts a separate thread of execution. Calling run() directly simply executes that method on the current thread.
4. Understanding Thread Constructors
A constructor initializes a thread object. Java provides several constructors in the Thread class so that a thread can be created with a default name, a custom name, a task, or a combination of a task and a name.
4.1 Common Thread Constructors
| Constructor |
Description |
Thread() |
Creates a thread object with a default generated name. |
Thread(String name) |
Creates a thread with the specified name. |
Thread(Runnable target) |
Creates a thread that executes the specified Runnable task. |
Thread(Runnable target, String name) |
Creates a thread with a task and a custom name. |
Thread(ThreadGroup group, Runnable target) |
Creates a thread associated with a specified thread group and task. |
Thread(ThreadGroup group, Runnable target, String name) |
Creates a thread with a group, task, and name. |
The Thread class has additional constructors for thread groups, stack-size hints, and inheritable thread-local settings. The constructors most commonly used in beginner programs are the default, named, Runnable, and Runnable-with-name forms.
4.2 Using the Default Constructor
The default constructor creates a thread object without an explicitly supplied task or name. When the thread starts, its own run() implementation is executed. If no task is supplied and the class does not override run(), there is no custom task to perform.
class Worker extends Thread {
@Override
public void run() {
System.out.println("Worker is running");
}
}
public class Main {
public static void main(String[] args) {
Worker worker = new Worker();
worker.start();
}
}
Output:
Worker is running
4.3 Using the Thread Constructor with a Name
The Thread(String name) constructor assigns a readable name to a thread. Meaningful names make debugging and monitoring easier.
class ReportThread extends Thread {
ReportThread(String name) {
super(name);
}
@Override
public void run() {
System.out.println("Running thread: " + getName());
}
}
public class Main {
public static void main(String[] args) {
ReportThread t1 = new ReportThread("Report-Worker");
t1.start();
}
}
Possible output:
Running thread: Report-Worker
The call to super(name) invokes the parent Thread constructor and sets the thread's name.
4.4 Using the Runnable Constructor
The Runnable interface represents a task that can be executed by a thread. Passing a Runnable object to a Thread constructor separates the task from the thread that runs it.
class PrintTask implements Runnable {
@Override
public void run() {
System.out.println("Runnable task is executing");
}
}
public class Main {
public static void main(String[] args) {
PrintTask task = new PrintTask();
Thread t1 = new Thread(task);
t1.start();
}
}
Explanation: The PrintTask class defines the task, while the Thread object manages its execution.
4.5 Using Runnable with a Custom Thread Name
public class Main {
public static void main(String[] args) {
Runnable task = () ->
System.out.println(
"Executing on: " +
Thread.currentThread().getName()
);
Thread t1 = new Thread(task, "Download-Worker");
t1.start();
}
}
Possible output:
Executing on: Download-Worker
This constructor is useful when the task logic should remain separate from thread configuration.
5. Thread Naming and Identification
Thread names help developers identify which thread is executing a task. Java automatically assigns a name when a platform thread is created without a custom name.
Important Naming Methods
| Method |
Purpose |
getName() |
Returns the thread's name. |
setName(String name) |
Changes the thread's name. |
currentThread() |
Returns a reference to the currently executing thread. |
threadId() |
Returns the thread's identifier in modern Java versions. |
public class Main {
public static void main(String[] args) {
Thread t1 = new Thread(
() -> System.out.println(
Thread.currentThread().getName()
)
);
t1.setName("Data-Processor");
t1.start();
}
}
Output:
Data-Processor
Set a custom name before starting a thread when possible, so logs and diagnostic information are easier to interpret.
6. Understanding Thread Priorities
Thread priority is a numeric hint that may influence how the JVM or operating system schedules threads. In Java, priority values range from 1 to 10 for platform threads.
6.1 Priority Constants
| Constant |
Value |
Description |
Thread.MIN_PRIORITY |
1 |
Minimum priority. |
Thread.NORM_PRIORITY |
5 |
Normal default priority. |
Thread.MAX_PRIORITY |
10 |
Maximum priority. |
6.2 Setting a Thread Priority
The setPriority(int priority) method sets the priority of a thread, and getPriority() retrieves it.
public class Main {
public static void main(String[] args) {
Thread t1 = new Thread(() ->
System.out.println("Low-priority task")
);
Thread t2 = new Thread(() ->
System.out.println("High-priority task")
);
t1.setPriority(Thread.MIN_PRIORITY);
t2.setPriority(Thread.MAX_PRIORITY);
System.out.println("T1 priority: " + t1.getPriority());
System.out.println("T2 priority: " + t2.getPriority());
t1.start();
t2.start();
}
}
Possible output:
T1 priority: 1
T2 priority: 10
High-priority task
Low-priority task
The execution order shown above is only an example. The actual order is not guaranteed. A higher priority does not ensure that a thread executes first or receives a fixed amount of CPU time.
6.3 Important Rules for Thread Priority
- Thread priority is a scheduling hint, not a strict execution order.
- The default priority for a newly created platform thread is generally inherited from the creating thread, subject to applicable thread-group limits.
- Priority values outside the supported range cause an
IllegalArgumentException.
- Do not use thread priority as the primary mechanism for coordinating tasks.
- Virtual threads have a fixed priority, so their priority cannot be changed.
7. Important Thread Methods
The Thread class provides methods to start a thread, inspect its status, pause its execution temporarily, wait for completion, and respond to interruption.
| Method |
Description |
start() |
Schedules a thread to begin execution. |
run() |
Contains the task performed by the thread. |
sleep(long millis) |
Temporarily pauses the currently executing thread. |
join() |
Waits for a thread to finish. |
isAlive() |
Checks whether a thread has started and has not yet terminated. |
currentThread() |
Returns the currently executing thread. |
getName() |
Gets the thread's name. |
setName(String name) |
Sets the thread's name. |
getPriority() |
Returns the thread's priority. |
setPriority(int priority) |
Changes a platform thread's priority within supported limits. |
getState() |
Returns the thread's current state snapshot. |
interrupt() |
Interrupts a thread, typically to request that it stop waiting or respond to cancellation. |
yield() |
Hints that the current thread is willing to yield its current use of a processor. |
8. Understanding start() and run()
Although both methods are associated with thread execution, they serve different purposes.
start() asks the JVM to schedule a new thread of execution.
run() contains the task's code. Calling it directly does not create a new thread.
public class Main {
public static void main(String[] args) {
Thread t1 = new Thread(() ->
System.out.println(
"Executing on: " +
Thread.currentThread().getName()
)
);
t1.run(); // Executes on the main thread
t1.start(); // Executes on a new thread
}
}
Possible output:
Executing on: main
Executing on: Thread-0
The automatically generated thread name may vary. A thread object can be started only once; calling start() again on the same thread object throws IllegalThreadStateException.
9. Using sleep() to Pause a Thread
The static Thread.sleep() method pauses the currently executing thread for a specified time. It can throw InterruptedException, which should be handled appropriately.
public class Main {
public static void main(String[] args) {
for (int i = 1; i <= 3; i++) {
System.out.println("Step " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Task interrupted");
return;
}
}
}
}
Explanation: The loop prints three steps, with an approximate one-second pause between them. Sleep timing depends on the system scheduler and timer precision.
Important: sleep() does not release any monitor locks that the current thread holds.
10. Using join() to Coordinate Threads
The join() method lets one thread wait for another thread to complete. It is useful when a result should be processed only after a background task finishes.
public class Main {
public static void main(String[] args) {
Thread worker = new Thread(() -> {
for (int i = 1; i <= 3; i++) {
System.out.println("Worker step " + i);
}
});
worker.start();
try {
worker.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
System.out.println("Worker has finished");
}
}
Explanation: The main thread waits until the worker completes before printing the final message.
11. Checking Thread Status with isAlive() and getState()
The isAlive() method returns true if a thread has started and has not yet terminated. The getState() method returns a snapshot of its state, which may change immediately after the call.
public class Main {
public static void main(String[] args) {
Thread worker = new Thread(() -> {
System.out.println("Task running");
});
System.out.println(worker.isAlive());
worker.start();
System.out.println(worker.isAlive());
try {
worker.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
System.out.println(worker.isAlive());
System.out.println(worker.getState());
}
}
The first isAlive() result is false, and after the thread has completed, it is again false. The intermediate result depends on timing because the thread may finish quickly.
12. Thread Interruption
Interruption is a cooperative mechanism used to request that a thread stop waiting or respond to cancellation. It does not forcibly terminate a thread.
public class Main {
public static void main(String[] args) {
Thread worker = new Thread(() -> {
try {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("Working...");
Thread.sleep(500);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Worker interrupted");
}
});
worker.start();
worker.interrupt();
}
}
In real applications, coordinate interruption carefully so that the task has a chance to clean up resources and exit safely. If a blocking method throws InterruptedException, the interrupt status is cleared by that exception; re-interrupting is appropriate when the code cannot fully handle the cancellation request.
13. Thread States
Java defines the following states through the Thread.State enumeration:
| State |
Description |
NEW |
The thread object has been created but not started. |
RUNNABLE |
The thread is executing or is eligible to execute, depending on scheduling. |
BLOCKED |
The thread is waiting to acquire a monitor lock. |
WAITING |
The thread is waiting indefinitely for another action. |
TIMED_WAITING |
The thread is waiting for a specified period. |
TERMINATED |
The thread has completed execution. |
These states describe the thread's observable lifecycle. A thread in the RUNNABLE state is not necessarily running on a CPU at the exact moment the state is checked.
14. Complete Example: Constructors, Names, Priorities, and Methods
public class Main {
public static void main(String[] args) {
Runnable task = () -> {
Thread current = Thread.currentThread();
System.out.println("Name: " + current.getName());
System.out.println("Priority: " + current.getPriority());
for (int i = 1; i <= 3; i++) {
System.out.println(
current.getName() + " - step " + i
);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
current.interrupt();
System.out.println("Task interrupted");
return;
}
}
};
Thread t1 = new Thread(task, "Worker-One");
Thread t2 = new Thread(task, "Worker-Two");
t1.setPriority(Thread.NORM_PRIORITY);
t2.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Main thread interrupted");
return;
}
System.out.println("All tasks completed");
}
}
Expected behavior: Both worker threads print their names and priorities, then process three steps each. Their messages may interleave in different orders because the scheduler controls execution. The main thread prints the final message after both workers finish.
15. Common Mistakes and Troubleshooting
| Mistake |
Why It Is a Problem |
Correct Approach |
Calling run() instead of start() |
The task executes on the current thread. |
Call start() to schedule a new thread. |
| Starting the same thread twice |
Throws IllegalThreadStateException. |
Create a new Thread object for another execution. |
| Assuming priority determines exact order |
Scheduling order is not guaranteed. |
Use coordination mechanisms such as join(), locks, or higher-level concurrency utilities. |
Ignoring InterruptedException |
Cancellation requests may be lost. |
Handle the interruption or restore the interrupt status. |
Using sleep() to coordinate tasks |
Timing varies across environments. |
Use synchronization or explicit coordination. |
| Sharing mutable data without synchronization |
Can cause race conditions and visibility problems. |
Use appropriate synchronization, locks, atomic variables, or concurrent utilities. |
16. Best Practices for Working with Threads
- Give threads descriptive names to make debugging easier.
- Prefer implementing
Runnable or using an executor when task logic should be separated from thread management.
- Use
start() to begin concurrent execution.
- Do not depend on thread priority for correctness or predictable ordering.
- Use
join() when one thread must wait for another to complete.
- Handle interruption as a cooperative cancellation signal.
- Protect shared mutable data with suitable concurrency mechanisms.
- For applications with many tasks, consider
ExecutorService rather than creating unlimited threads manually.
- Remember that
getState() is a snapshot, not a synchronization mechanism.
17. Practice Exercises
- Create a thread using the default Thread constructor and override
run().
- Create a thread using
Thread(String name) and print its name.
- Pass a Runnable task to
Thread(Runnable target, String name).
- Set two platform threads to minimum and maximum priorities and display their priority values.
- Use
sleep() to pause a task between printed messages.
- Use
join() to make the main thread wait for a worker.
- Print the current thread name and state at suitable points in a program.
- Build a small background task that responds appropriately to interruption.
18. Mini Project: Background Report Generator
Objective: Create a small Java program that simulates generating a report in a background thread.
Requirements
- Create a Runnable task that prints five report-generation steps.
- Create a Thread with the name
Report-Generator.
- Set its priority to
Thread.NORM_PRIORITY.
- Use
sleep() to simulate work between steps.
- Use
join() so the main thread waits for report generation to finish.
- Handle interruption and restore the interrupt status when appropriate.
Sample Implementation
public class ReportGenerator {
public static void main(String[] args) {
Runnable reportTask = () -> {
for (int i = 1; i <= 5; i++) {
System.out.println("Generating report: " + i);
try {
Thread.sleep(400);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Report generation cancelled");
return;
}
}
System.out.println("Report generated successfully");
};
Thread reportThread =
new Thread(reportTask, "Report-Generator");
reportThread.setPriority(Thread.NORM_PRIORITY);
reportThread.start();
try {
reportThread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Waiting was interrupted");
return;
}
System.out.println("Main program finished");
}
}
19. Interview Questions and Answers
Q1. What is the Thread class in Java?
The Thread class represents a thread of execution and provides methods for starting, naming, monitoring, and managing threads.
Q2. What is a thread constructor?
A thread constructor initializes a Thread object, optionally providing a task, a name, a thread group, or other configuration.
Q3. What is the difference between Thread() and Thread(String name)?
Thread() creates a thread with a generated name, whereas Thread(String name) assigns a specified name.
Q4. What is the difference between Thread(Runnable) and Thread(Runnable, String)?
Both accept a Runnable task. The second constructor also assigns a custom name to the thread.
Q5. What are thread priorities?
Thread priorities are scheduling hints. Platform-thread priorities normally range from 1 to 10, but they do not guarantee execution order.
Q6. What are MIN_PRIORITY, NORM_PRIORITY, and MAX_PRIORITY?
They represent priority values 1, 5, and 10, respectively.
Q7. What is the difference between start() and run()?
start() schedules a new thread of execution, while directly calling run() executes the method on the current thread.
Q8. What does sleep() do?
sleep() pauses the currently executing thread for a specified period, subject to scheduling and timer precision.
Q9. What does join() do?
join() allows the calling thread to wait until another thread terminates.
Q10. Can a thread be started more than once?
No. A Thread object can be started only once. Starting it again throws IllegalThreadStateException.
Q11. Does a higher-priority thread always execute first?
No. Priority is a hint to the scheduler and cannot guarantee execution order or CPU time.
Q12. What is interruption in Java?
Interruption is a cooperative signal that allows a thread to respond to cancellation or stop waiting in interruptible operations.
20. Quick Revision Checklist
Thread() creates a thread with a generated name.
Thread(String name) creates a named thread.
Thread(Runnable task) associates a task with a thread.
Thread(Runnable task, String name) associates a task with a named thread.
start() schedules a new thread of execution.
run() contains the task logic.
setPriority() and getPriority() configure and inspect platform-thread priority.
getName() and setName() retrieve and change a thread's name.
sleep() pauses the current thread temporarily.
join() waits for another thread to finish.
isAlive() checks whether a thread is active.
interrupt() requests cooperative interruption.
- Priorities do not guarantee execution order.
21. Conclusion
Thread constructors, priorities, and methods are fundamental concepts in Java multithreading. Constructors help initialize threads with tasks and meaningful names, priorities provide scheduling hints, and methods such as start(), sleep(), join(), isAlive(), and interrupt() support thread execution and coordination.
For reliable concurrent programs, understand the difference between starting a thread and calling its run method, handle interruptions carefully, avoid relying on priorities for correctness, and protect shared data with appropriate synchronization techniques.
22. Additional Learning Resources